Error whoch is of non-class type. Most vexing parse

Intro

C++ is a weird tricky thing which sometimes make me mad. One day I write a class which accepts a const std::list<std::string> & as first and only one parameter. And then I instantiated this class like this A(std::list<std::string>()). Ang got a compile error like in the subj.

Problem isolated

Lets look at sample:

#include <list>
#include <string>

using namespace std;

class A {
public:
  A(const std::list<std::string> &l) {
  }

  int foo() {
    return 10;
  }
};


int main(int argc, char **argv) {
  A a(std::list<std::string>()); // the root of evil

  a.foo();  // and here we get an error
}

The result of compilation of this sample will be the next in gcc:

~/exp $ g++ one.cpp
 one.cpp: In function ‘int main(int, char**)’:
 one.cpp:20:5: error: request for member ‘foo’ in ‘a’, which is of non-class type ‘A(std::list<std::basic_string<char> > (*)())’
 a.foo();

'Debugging' the solution

CLang usualy have a way better error messages than a gcc. So I used it on this sample to see what will happen:

~/exp $ clang++ one.cpp
one.cpp:18:6: warning: parentheses were disambiguated as a function declaration [-Wvexing-parse]
  A a(std::list<std::string>());
     ^~~~~~~~~~~~~~~~~~~~~~~~~~
one.cpp:18:7: note: add a pair of parentheses to declare a variable
  A a(std::list<std::string>());
      ^
      (                       )
one.cpp:20:4: error: member reference base type 'A (std::list<std::string> (*)())' is not a structure or union
  a.foo();
  ~^~~~
1 warning and 1 error generated.

Here we see 3 very usefull suggestions:

Vexing parse

This issue is easy to 'google' by a search 'vexing parse c++'. The problem here is with temporary objects passed to a constructor - such initialization line is got by a compiler as a function declaration. To disambiguate this we can use 3 approaches.

Call of ctor through cast

The ctor with one param is assumed to be a cast operator from type B which is type of param into class type A. For example:

struct A {
    int m_a;
public:
    A(int a)
        : m_a(a) {
    }
};

// somewhere in code
A a = 10;

So to make our sample compile we have to use next transformation:

  A a = std::list<std::string>(); // the root of evil

To restrict such behaviour of ctor with one parameter you can use explicit keyword.

```c++ struct A { int ma; public: explicit A(int a) // note explicit here : ma(a) { } };

// somewhere in code A a = 10; // will make a compile error ```

Additional pair of brackets

Also we can disambiguate this declaration by adding additional pair of brackets:

  A a((std::list<std::string>())); // the root of evil

static_cast

Very simple straightforward solution - no casts can appear in function declaration so we do next:

  A a(static_cast<std::list<std::string> >(std::list<std::string>())); // the root of evil

CXX 011 unified initialization

You see all this ugly stuff and think that this is language issue. So commitet got a solution to it. To compile cxx11 programms you have to specify a language standart to your compiler.

g++ --std=c++11 one.cpp

The code changes is very simple:

A a{std::list<std::string>{}}; // the root of evil

They extended a list initialization syntax and make it unified for all the operations of initialization.